package org.adream.account.service;

import java.util.List;

import org.adream.account.dao.LoginDao;
import org.adream.account.dao.LoginStateDao;
import org.adream.account.dao.RealNameAuthDao;
import org.adream.account.dao.SchoolDao;
import org.adream.account.dao.UserDao;
import org.adream.account.entity.LoginStateEntity;
import org.adream.account.entity.RealNameAuthEntity;
import org.adream.account.entity.SchoolEntity;
import org.adream.account.entity.UserEntity;
import org.adream.account.model.LoginModel;
import org.adream.account.model.ResultModel;
import org.adream.account.restful.vo.UserVO;
import org.adream.account.util.Constant;
import org.adream.account.util.PasswordUtil;
import org.adream.account.util.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

@Service
public class LoginService {

	private final static Logger logger = LoggerFactory.getLogger(LoginService.class);

	@Autowired
	private LoginDao loginDao;
	
	@Autowired
	private UserDao userDao;
	
	@Autowired
	private LoginStateDao loginStateDao;
	
	@Autowired
	private RealNameAuthDao authDao;
	
	@Autowired
	private SchoolDao schoolDao;

	/**
	 * 新增登录方式
	 * @param loginModel
	 * @return
	 */
	public ResultModel<String> addLogin(LoginModel loginModel) {
		int result = loginDao.addLogin(loginModel);
		if(result == 0) {
			logger.warn("新增登录方式数据失败,数据库错误,login:{}", loginModel.getLogin());
			return new ResultModel<String>(ResultModel.ERR_SYS, "系统错误,请联系系统管理员", null);
		}
		return new ResultModel<String>(ResultModel.SUCCESS, ResultModel.SUCCESS_MSG, null);
	}

	/**
	 * 删除  通过登录方式
	 * @param login
	 */
	public ResultModel<String> deleteLoginByLogin(String login) {
		int result = loginDao.deleteLoginByLogin(login);
		if(result == 0) {
			logger.warn("通过login删除登录方式失败,数据库错误,login:{}", login);
			return new ResultModel<String>(ResultModel.ERR_SYS, "系统错误,请联系系统管理员", null);
		}
		return new ResultModel<String>(ResultModel.SUCCESS, ResultModel.SUCCESS_MSG, null);
	}

	/**
	 * 删除   根据uid
	 * @param uid
	 */
	public ResultModel<String> deleteLoginByUid(String uid) {
		int result = loginDao.deleteLoginByUid(uid);
		if(result == 0) {
			logger.warn("通过uid删除登录方式失败,数据库错误,uid:{}", uid);
			return new ResultModel<String>(ResultModel.ERR_SYS, "系统错误,请联系系统管理员", null);
		}
		return new ResultModel<String>(ResultModel.SUCCESS, ResultModel.SUCCESS_MSG, null);
	}

	/**
	 * 根据uid更新 密码
	 * @param loginModel
	 */
	public ResultModel<String> updateLoginByUid(LoginModel loginModel) {
		List<LoginModel> logins = loginDao.queryLoginByUid(loginModel.getUid());
		//微信浏览器端打开,进行手机绑定,cas_login无记录
		//cas_login添加手机号登录记录
		if(Utils.isEmptyCollection(logins)) {
			UserEntity user = userDao.queryUserByDrAndUid(Constant.ONE, loginModel.getUid());
			if(user == null || StringUtils.isEmpty(user.getPhone())) {
				logger.warn("新增手机登录方式失败,未查询到相应的用户,uid:{}", loginModel.getUid());
				return new ResultModel<String>(ResultModel.NOT_FOUND_OBJECT, "更新失败,用户不存在", null);
			}
			if(loginDao.queryLoginByLogin(loginModel.getLogin()) != null) {
				logger.warn("新增手机登录方式失败,已存在相应的登录方式,login:{}", loginModel.getLogin());
				return new ResultModel<String>(ResultModel.HAS_FOUND_OBJECT, "更新失败,手机号已被占用", null);
			}
			String salt = Utils.getSixUuid();
			loginModel.setLogin(user.getPhone());
			loginModel.setMethod(Constant.APWD);
			loginModel.setPassword(PasswordUtil.generate(loginModel.getPassword(), salt));
			loginModel.setSalt(salt);
			int result = loginDao.addLogin(loginModel);
			if(result == 0) {
				logger.warn("通过login删除登录方式失败,数据库错误,login:{}", loginModel.getLogin());
				return new ResultModel<String>(ResultModel.ERR_SYS, "系统错误,请联系系统管理员", null);
			}
		} else {	
			String salt = logins.get(0).getSalt();
			loginModel.setPassword(PasswordUtil.generate(loginModel.getPassword(), salt));
			loginModel.setMethod(Constant.APWD);
			loginModel.setSalt(salt);
			loginDao.updateLoginByUid(loginModel);
		}
		return new ResultModel<String>(ResultModel.SUCCESS, ResultModel.SUCCESS_MSG, null);
	}
	
	/**
	 * 更新,可更新登录方式
	 * @param loginModel
	 * @param oriLogin
	 */
	public ResultModel<String> updateLoginByOriLogin(LoginModel loginModel,String oriLogin) {
		int result = loginDao.updateLoginByOriLogin(loginModel, oriLogin);
		if(result == 0) {
			logger.warn("更新登录方式失败,数据库错误,oriLogin:{}", oriLogin);
			return new ResultModel<String>(ResultModel.ERR_SYS, "系统错误,请联系系统管理员", null);
		}
		return new ResultModel<String>(ResultModel.SUCCESS, ResultModel.SUCCESS_MSG, null);
	}

	/**
	 * 修改login的密码 ，盐保持原本不变
	 * 
	 * @param loginModel.getPassword()
	 * 			      登录方式不存在，判断后生成具体登录方式
	 *            为空则重置密码为 000000，不为空则修改密码
	 * @return
	 * @author chenhaoyu
	 * @throws ADreamServiceException 
	 */
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = ADreamServiceException.class, isolation = Isolation.DEFAULT)
	public void changeLoginPwdByUid(LoginModel loginModel) throws ADreamServiceException {
		logger.info("重置密码");
		if(StringUtils.isEmpty(loginModel) || StringUtils.isEmpty(loginModel.getUid())) {
			logger.info("重置失败,请求参数有误:)");
			throw new ADreamServiceException("重置失败,请求参数有误");
		}
		List<LoginModel> logins = loginDao.queryLoginByUid(loginModel.getUid());
		if(Utils.isEmptyCollection(logins)) {
			//微信端进入,绑定手机号 不存在login记录
			UserEntity user = userDao.queryUserByDrAndUid(Constant.ONE, loginModel.getUid());
			if(user == null || StringUtils.isEmpty(user.getPhone())) {
				logger.warn("重置失败,用户不存在:(");
				throw new ADreamServiceException("重置失败,用户不存在或手机号为空");
			}
			String phone = user.getPhone();
			String email = user.getEmail();
			LoginModel phoneLogin = loginDao.queryLoginByLogin(phone);
			//手机登录方式是否已被使用
			if(phoneLogin != null) {
				logger.warn("重置失败,手机号已被用户:" + phoneLogin.getUid() + " 使用");
				throw new ADreamServiceException("重置失败,手机号已被其他用户使用");
			}
			logger.info("生成—" + loginModel.getUid() + "—账密登录,初始密码:000000");
			//生成手机-密码 账密登录方式
			phoneLogin = new LoginModel();
			String newSalt = Utils.getSixUuid();
			phoneLogin.setLogin(phone);
			String md5 = PasswordUtil.generate(Constant.ORIPWD, newSalt);
			phoneLogin.setPassword(md5);
			phoneLogin.setSalt(newSalt);
			phoneLogin.setUid(user.getUid());
			phoneLogin.setMethod(Constant.APWD);
			loginDao.addLogin(phoneLogin);
			//email不为空  && 邮箱登录方式不存在
			if(!StringUtils.isEmpty(email) && loginDao.queryLoginByLogin(email) == null) {
				LoginModel emailLogin = phoneLogin;
				emailLogin.setLogin(email);
				loginDao.addLogin(emailLogin);
			}
			return;
		}
		//获取之前使用的盐
		String salt = Utils.getSixUuid();
		loginModel.setSalt(salt);
		loginModel.setMethod(Constant.APWD);
		
		if (!StringUtils.isEmpty(loginModel.getPassword())) {  //修改密码
			logger.info("修改—" + loginModel.getUid() + "-密码");
			String pwd = PasswordUtil.generate(loginModel.getPassword(), salt);
			loginModel.setPassword(pwd);
			loginDao.updateLoginByUid(loginModel);
		} else {
			logger.info("重置—" + loginModel.getUid() + "-密码为初始密码： 000000");   //重置密码
			String pwd = PasswordUtil.generate(Constant.ORIPWD, salt);
			loginModel.setPassword(pwd);
			loginDao.updateLoginByUid(loginModel);
		}
		//重置密码或修改密码,登录密码错误次数重置
		LoginStateEntity loginState = loginStateDao.queryLoginStateByUid(loginModel.getUid());
		if(loginState != null) {
			loginState.setWrongTimes(Constant.ZERO);
			int result = loginStateDao.updateWrongTimes(loginState);
			if(result == Constant.ZERO) {
				logger.warn("重置登录密码次数失败:(");
				throw new ADreamServiceException("重置登录密码次数失败");
			}
		}
	}

	/**
	 * 通过登录方式查询login
	 * @param login
	 * @return
	 */
	public LoginModel queryLoginByLogin(String login) {
		return loginDao.queryLoginByLogin(login);
	}

	/**
	 * 通过uid查询login,一般user有多种登录方式
	 * 
	 * @param uid
	 * @return
	 */
	public List<LoginModel> queryLoginByUid(String uid) {
		return loginDao.queryLoginByUid(uid);
	}

	/**
	 * 检查用户密码
	 * @param uid
	 * @param password
	 * @return
	 */
	public boolean checkPassword(String uid, String password) {
		boolean isValidPwd = false;
		List<LoginModel> logins = loginDao.queryLoginByUid(uid);
		if (Utils.isEmptyCollection(logins)) {
			return false;
		}
		LoginModel login = logins.get(0);
		String oriPassword = login.getPassword();
		String salt = login.getSalt();
		String method = login.getMethod();
		isValidPwd = PasswordUtil.verifyPwd(password, salt, method, oriPassword);
		return isValidPwd;
	}
	
	/**
	 * 重置密码
	 * @param login	登录方式
	 * @param password	密码
	 * @throws ADreamServiceException
	 */
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class, isolation = Isolation.DEFAULT)
	public ResultModel<String> resetPassword(String login,String password) {
		//查询是否存在对应的登录记录
		String uid = loginDao.queryUidByLogin(login);
		if(StringUtils.isEmpty(uid)) {
			//未查询到相应的登录记录
			//根据login查询用户表是否存在对应的信息
			UserEntity phoneUser = userDao.queryUserByPhone(login);
			UserEntity emailUser = userDao.queryUserByEmail(login);
			if(phoneUser == null && emailUser == null) {
				logger.warn("重置密码失败,未查询到相应用户uid,login:{}", login);
				return new ResultModel<String>(ResultModel.NOT_FOUND_OBJECT, "更新失败，用户不存在", null);
			}
			//创建对应的登录记录
			LoginModel loginModel = new LoginModel();
			loginModel.setLogin(login);
			String salt = Utils.getSixUuid();
			loginModel.setPassword(PasswordUtil.generate(password, salt));
			loginModel.setSalt(salt);
			loginModel.setUid(phoneUser != null ? phoneUser.getUid() : emailUser.getUid());
			loginModel.setMethod(Constant.APWD);
			loginDao.replaceLogin(loginModel);
		} else {
			List<LoginModel> loginModels = loginDao.queryLoginByUid(uid);
			if(!Utils.isEmptyCollection(loginModels)) {
				//使用同一种盐
				String salt = Utils.getSixUuid();
				String pwd = PasswordUtil.generate(password, salt);
				loginModels.forEach(loginModel -> {
					loginModel.setPassword(pwd);
					loginModel.setSalt(salt);
					loginModel.setMethod(Constant.APWD);
					loginDao.replaceLogin(loginModel);
				});
			}
		}
		return new ResultModel<String>(ResultModel.SUCCESS, "更换密码成功", null);
	}
	
	/**
	 * 验证用户名,密码是否正确
	 * @param un	用户名
	 * @param pd	密码
	 * @return
	 */
	public ResultModel<String> checkUserInfo(String un,String pd) {
		LoginModel loginModel = loginDao.queryLoginByLogin(un);
		if(loginModel == null) {
			logger.warn("验证出错,未查询到相应的登录信息");
			return new ResultModel<String>(ResultModel.NOT_FOUND_OBJECT, ResultModel.NOT_FOUND_OBJECT_MSG, null);
		}
		String salt = loginModel.getSalt();
		String password = loginModel.getPassword();
		if(password != null) {			
			if(password.equals(PasswordUtil.generate(pd, salt)) 
					|| password.equals(PasswordUtil.generate(salt, pd))
					|| password.equals(PasswordUtil.generate(PasswordUtil.generate(pd, ""), salt))) {
				return new ResultModel<String>(ResultModel.SUCCESS,ResultModel.SUCCESS_MSG,loginModel.getUid());
			}
		}
		return new ResultModel<String>(ResultModel.ERR_USER_INFO, "验证出错,密码错误", null);
	}
	
	/**
	 * 	智慧课堂 登陆
	 * @param un
	 * @param pd
	 * @return
	 */
	public UserVO doLogin(String un,String pd) {
		//查询用户名-密码登录方式
		LoginModel loginModel = loginDao.queryLoginByLogin(un);
		if(loginModel == null) {
			logger.warn("验证出错,未查询到相应的登录信息");
			return null;
		}
		String salt = loginModel.getSalt();
		String password = loginModel.getPassword();
		if(password != null) {			
			if(password.equals(PasswordUtil.generate(pd, salt)) 
					|| password.equals(PasswordUtil.generate(salt, pd))
					|| password.equals(PasswordUtil.generate(PasswordUtil.generate(pd, ""), salt))) {
				String uid = loginModel.getUid();
				//查询用户信息
				UserEntity userEntity = userDao.queryUserByUid(uid);
				if(userEntity == null) {
					return null;
				}
				UserVO userVO = new UserVO();
				Utils.copyPropertiesIgnoreNull(userEntity, userVO);
				
				//查询实名信息
				RealNameAuthEntity realNameAuthEntity = authDao.queryAuthByUid(uid);
				 
				if(realNameAuthEntity!=null) {
					userVO.setRealName(realNameAuthEntity.getRealName());
				}
				//查询对应学校信息
				SchoolEntity schoolEntity = schoolDao.queryMySchoolByUid(userVO.getUid());
				if(schoolEntity !=null) {
					userVO.setSid(schoolEntity.getSid());
					userVO.setSname(schoolEntity.getSname());
					userVO.setProvince(schoolEntity.getSchoolProvince());
					userVO.setCity(schoolEntity.getSchoolCity());
					userVO.setArea(schoolEntity.getSchoolArea());
				}
				return userVO;
			}
		}
		return null;
	}
}